home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1994 November: Tool Chest / Dev.CD Nov 94.toast / Tool Chest / QuickDraw GX / QuickDraw GX Info / QuickDraw GX Interfaces / Interfaces & Libraries / graphics libraries / layout library.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-04-30  |  15.5 KB  |  496 lines  |  [TEXT/MPS ]

  1. /* layout library.c -- Line Layout library routines.
  2.     
  3. CHANGE LOG
  4.  
  5. Date      Person      Action
  6. ----      ------      ------
  7.  
  8. 900517    ERM       • Created.
  9. 900702    ERM       • Converted to new graphics-like interface.
  10. 900703    ERM       • Add LineOptions parameter to SingleLayout guys.
  11. 900712    DGO       • Fixed NewEasyLayout, which wasn't correctly doing LineOptions.
  12. 900731    DGO       • Changed "line" to "lineOpts" throughout.
  13.                     • Added code to initialize controls in SetLayoutStyle if passed-in
  14.                       parameter "layoutControls" is nil.
  15. 900803    ERM       • Removed controls initialization from NewSingleLayout.
  16.                     • Various other formatting clean-up.
  17. 900826    DGO       • Added first cut at the paragraph functions.
  18. 900828    DGO       • Fixed sense-of-sign bug. *BLUSH*
  19. 900912    ERM       • Bagged references to hard-coded layout feature levels.
  20. 900914    ERM       • Added GetStyleLayoutFeatureNames.
  21. 900917    ERM       • THINK C 3.0 compatability changes.
  22. 910114    DGO       • Removed overhangRect references.
  23. 910410    DGO       • Merged Mike's changes to font manager.
  24.                     • Added lineHeight parameter to NewParagraph.
  25. 910415    ERM + DGO • Added include of ToolUtils.
  26. 910516    OWS       • Converted to ANSI-style function declarations.
  27.                     • Updated includes for Think C 5.0.
  28. 910529    DGO       • Changed to final 1.0 form.
  29. 910626    DGO       • Bug fixing in NewParagraph (undisposed shape, bad pointer).
  30. 910820    DGO       • Added NewDiscontiguousSelection function.
  31.                     • Minor name changes.
  32. 911118    ERM       • Replaced GetStyleRunFeatureNames w/ GetStyleRunFeatureTypeNames, GetStyleRunFeatureSelectorNames.
  33. 911120    ERM       • Removed gxRunFeatureType from RunFeatureSelectorName.
  34. 911124    DGO       • Moved NewDiscontiguousSelection to selection library.
  35. 920309    ERM       • GXNewLayout now has explicit run counts.
  36. 920505    DGO       • Fixed NewStyledParagraph linebreaking bug.
  37. 930623        DGO                •    Added GXIgnoreGraphicsNotice for text_attributes_already_set.
  38.  
  39. */
  40.  
  41. /* Copyright ©1990-1993 Apple Computer, Inc.  All rights reserved. */
  42.  
  43. #include <Types.h>
  44. #include <Memory.h>
  45. #include <Resources.h>
  46. #include <ToolUtils.h>
  47.  
  48. #include "graphics routines.h"
  49. #include "math routines.h"
  50. #include "layout types.h"
  51. #include "layout routines.h"
  52. #include "layout library.h"
  53. #include "font routines.h"
  54. #include "font library.h"
  55.  
  56. void InitializeLayoutOptions (gxLayoutOptions *layoutOptions)
  57. { layoutOptions->width = 0;
  58.   layoutOptions->flush = 0;
  59.   layoutOptions->just = 0;
  60.   layoutOptions->flags = 0;
  61.   layoutOptions->baselineRec = nil;
  62. }
  63.  
  64. void SetDefaultPriorityJustOverride (gxPriorityJustificationOverride *override)
  65. { short i;
  66.   gxWidthDeltaRecord  *pDelta;
  67.  
  68.   pDelta = override->deltas;
  69.   for (i = 0; i < gxNumberOfJustificationPriorities; i++)
  70.   { pDelta->growFlags = pDelta->shrinkFlags = 0;
  71.     pDelta->beforeGrowLimit = pDelta->afterGrowLimit = 
  72.       pDelta->beforeShrinkLimit = pDelta->afterShrinkLimit = 0;
  73.     pDelta++;
  74.   } /* endloop i */
  75. }
  76.  
  77. void InitializeRunControls (gxRunControls *runControls)
  78. { runControls->flags = 0;
  79.   runControls->beforeWithStreamShift = runControls->afterWithStreamShift = 0;
  80.   runControls->crossStreamShift = 0;
  81.   runControls->imposedWidth = 0;
  82.   runControls->track = 0;
  83.   runControls->hangingInhibitFactor = runControls->kerningInhibitFactor = 0;
  84.   runControls->baselineType = gxRomanBaseline;
  85.   runControls->decompositionAdjustmentFactor = 0;
  86. }
  87.  
  88. void InitializeStyleRunOverrides (StyleRunOverrides *overrides)
  89. { overrides->priorityJustOverride = nil;
  90.   overrides->glyphJustOverrides = nil;
  91.   overrides->glyphJustOverridesCount = 0;
  92.   overrides->glyphSubstitutions = nil;
  93.   overrides->glyphSubstitutionsCount = 0;
  94.   overrides->kerningAdjustments = nil;
  95.   overrides->kerningAdjustmentsCount = 0;
  96. }
  97.  
  98. static void SetStyleNamedFont(gxStyle s, unsigned char* name)
  99. {
  100.   gxFont fontID = FindPNameFont(gxFullFontName, name);
  101.   if (fontID != GXGetStyleFont(s))
  102.     GXSetStyleFont(s, fontID);
  103. }
  104.  
  105. void SetLayoutStyle (
  106.   gxStyle             s,
  107.   char              *gxFontName,
  108.   Fixed             textSize,
  109.   gxTextAttribute     attr,
  110.   gxRunControls       *runControls,
  111.   gxRunFeature        runFeatures[],
  112.   long              runFeaturesCount,
  113.   StyleRunOverrides *overrides)
  114. { gxRunControls localControls;
  115.  
  116. #ifdef debugging  
  117.   GXIgnoreGraphicsNotice(attributes_already_set);
  118.   GXIgnoreGraphicsNotice(text_attributes_already_set);
  119. #endif
  120.  
  121.   SetStyleNamedFont (s, (unsigned char*)gxFontName);
  122.   GXSetStyleTextSize (s, textSize);
  123.   GXSetStyleTextAttributes (s, attr);
  124.  
  125.   if (!runControls)
  126.   { InitializeRunControls(&localControls);
  127.     runControls = &localControls;
  128.   }
  129.   
  130.   GXSetStyleRunControls (s, runControls);
  131.  
  132.   if (runFeatures) GXSetStyleRunFeatures (s, runFeaturesCount, runFeatures);
  133.  
  134.   if (overrides)
  135.   { if (overrides->glyphSubstitutions)
  136.       GXSetStyleRunGlyphSubstitutions (s, overrides->glyphSubstitutionsCount, overrides->glyphSubstitutions);
  137.     if (overrides->kerningAdjustments)
  138.       GXSetStyleRunKerningAdjustments (s, overrides->kerningAdjustmentsCount, overrides->kerningAdjustments);
  139.     if (overrides->glyphJustOverrides)
  140.       GXSetStyleRunGlyphJustOverrides (s, overrides->glyphJustOverridesCount, overrides->glyphJustOverrides);
  141.     if (overrides->priorityJustOverride)
  142.       GXSetStyleRunPriorityJustOverride (s, overrides->priorityJustOverride);
  143.   }
  144. #ifdef debugging  
  145.   GXPopGraphicsNotice();
  146.   GXPopGraphicsNotice();
  147. #endif
  148. }
  149.  
  150. gxStyle NewLayoutStyle (
  151.   char              *gxFontName,
  152.   Fixed             textSize,
  153.   gxTextAttribute     attr,
  154.   gxRunControls       *runControls,
  155.   gxRunFeature        runFeatures[],
  156.   long              runFeaturesCount,
  157.   StyleRunOverrides *overrides)
  158. { gxStyle newStyle = GXNewStyle ();
  159.  
  160.   SetLayoutStyle (
  161.     newStyle,
  162.     gxFontName,
  163.     textSize,
  164.     attr,
  165.     runControls,
  166.     runFeatures,
  167.     runFeaturesCount,
  168.     overrides);
  169.   
  170.   return (newStyle);
  171. }
  172.  
  173. gxShape NewSingleLayout (
  174.   char              *text,
  175.   char              *gxFontName,
  176.   Fixed             textSize,
  177.   gxLayoutOptions     *options,
  178.   gxPoint             *position,
  179.   gxTextAttribute     attr,
  180.   gxRunControls       *runControls,
  181.   gxRunFeature        runFeatures[],
  182.   long              runFeaturesCount,
  183.   StyleRunOverrides *overrides)
  184. { gxStyle newLayoutStyle;
  185.   gxShape newLayoutShape;
  186.   short len, level = 0;
  187.   char  *s;
  188.   
  189.   newLayoutStyle = NewLayoutStyle (
  190.     gxFontName,
  191.     textSize,
  192.     attr,
  193.     runControls,
  194.     runFeatures,
  195.     runFeaturesCount,
  196.     overrides);
  197.  
  198.   for (len = 0, s = text; *s++ != 0; len++) ;
  199.   
  200.   newLayoutShape = GXNewLayout (
  201.     1,
  202.     &len,
  203.     (const void **) &text,
  204.     1,
  205.     &len,
  206.     &newLayoutStyle,
  207.     1,
  208.     &len,
  209.     &level,
  210.     options,
  211.     position);
  212.   
  213.   GXDisposeStyle (newLayoutStyle);
  214.   
  215.   return newLayoutShape;
  216. }
  217.  
  218. /* NewParagraph is the simplest of the paragraph creation functions. It assumes a single
  219.     gxStyle for the whole paragraph, and does its own deduction about where the paragraph
  220.     ends (namely at a hard stop, CR or HT). */
  221.  
  222. short CountBytes(char *text);
  223. short CountBytes(char *text)
  224.   {
  225.   short count = 0;
  226.   while (*text != 13 && *text != 9)
  227.     {text++; count++;}
  228.   return count;
  229.   } /* CountBytes */
  230.  
  231. ParagraphRecordHandle NewParagraph(
  232.   char    *text,
  233.   gxStyle   baseStyle,
  234.   Fixed   width,
  235.   long    justified,
  236.   Fixed   lineHeight,
  237.   gxPoint   *firstOrigin)
  238.   {
  239.   /* Constants */
  240.   #define extraLineGap ff(2)
  241.   #define lineStartsCount 50
  242.   /* Variables */
  243.   boolean               startIsStaked;
  244.   gxByteOffset            lineStarts[lineStartsCount], newLineStart, nextStake,
  245.                         nls2, priorStake, thisLineStart;
  246.   char                  *pChar;
  247.   Fixed                 currLineDelta, textSize;
  248.   gxLayoutOptions         options;
  249.   ParagraphRecordHandle paraHandle;
  250.   gxShape                 bigLayout, thisLine;
  251.   short                 byteCount, i, level = 0, nextLineIndex;
  252.   
  253.   byteCount = CountBytes(text); /* doesn't count the CR or HT!! */
  254.   bigLayout = GXNewLayout(
  255.     1,
  256.     &byteCount,
  257.     (const void **) &text,
  258.     1,
  259.     &byteCount,
  260.     &baseStyle,
  261.     1,
  262.     &byteCount,
  263.     &level,
  264.     nil,
  265.     firstOrigin);
  266.   
  267.   /* We next compute the gxLine breaks and store the offsets that correspond to them in a
  268.       temporary array. */
  269.   
  270.   thisLineStart = 0;
  271.   nextLineIndex = 0;
  272.   while (thisLineStart < byteCount && nextLineIndex < lineStartsCount - 1)
  273.     {
  274.     lineStarts[nextLineIndex++] = thisLineStart;
  275.     newLineStart = GXGetLayoutBreakOffset(
  276.       bigLayout, thisLineStart, width, 0, nil, &startIsStaked, &priorStake, &nextStake);
  277.     if (newLineStart == byteCount) break;
  278.     /* Now backtrack to first prior space. */
  279.     nls2 = newLineStart;
  280.     pChar = text + newLineStart - 1;
  281.     while (nls2 >= 0 && *pChar != ' ')
  282.       {
  283.       pChar--;
  284.       nls2--;
  285.       }
  286.     if (nls2 < 0) thisLineStart = newLineStart;
  287.     else thisLineStart = nls2;
  288.     }
  289.   lineStarts[nextLineIndex] = byteCount;
  290.   
  291.   /* Allocate space for the ParagraphRecord. */
  292.   
  293.   paraHandle = (ParagraphRecordHandle) NewHandle(
  294.     (Size) (sizeof(ParagraphRecord) + nextLineIndex * sizeof(gxShape)));
  295.   (*paraHandle)->nLayouts = nextLineIndex;
  296.   
  297.   /* Now create the layouts and place them in the ParagraphRecord. */
  298.   
  299.   InitializeLayoutOptions(&options);
  300.   options.width = width;
  301.   if (justified) options.just = fract1;
  302.   textSize = GXGetStyleTextSize(baseStyle);
  303.   currLineDelta = 0;
  304.   
  305.   for (i = 0; i < nextLineIndex; i++)
  306.     {
  307.     if (i == nextLineIndex - 1) options.just = 0; /* don't justify the last gxLine... */
  308.     thisLine = GXNewLayoutFromRange(
  309.       bigLayout, lineStarts[i], lineStarts[i+1], &options, nil);
  310.     if (currLineDelta) GXMoveShape(thisLine, 0, currLineDelta);
  311.     (*paraHandle)->layouts[i] = thisLine;
  312.     currLineDelta += (lineHeight ? lineHeight : (textSize + extraLineGap));
  313.     }
  314.   
  315.   (*paraHandle)->totalHeight = currLineDelta;
  316.   
  317.   GXDisposeShape(bigLayout);
  318.   return paraHandle;
  319.   } /* NewParagraph */
  320.  
  321. static char *GetTextPiecePtr(
  322.   const void    *text[],
  323.   const short   textRunLengths[],
  324.   short         offset)
  325.   
  326.   {
  327.   char  **pPiece = (char **) text;
  328.   short oCopy = offset;
  329.   short *runLength = (short *) textRunLengths;
  330.   while (oCopy > *runLength)
  331.     {oCopy -= *runLength++; pPiece++;}
  332.   return *pPiece + oCopy;
  333.   } /* GetTextPiecePtr */
  334.  
  335. static long GetPreviousOffset(gxShape layout, long offset)
  336. { unsigned short firstGlyph, secondGlyph;
  337.   gxLayoutOffsetState offsetState;
  338.   static long offsetStateSizes[] = {1, 1, 2, 2, 0};
  339.   
  340.   GXGetOffsetGlyphs(layout, offset, 0, &offsetState, &firstGlyph, &secondGlyph);
  341.   
  342.   return offset - offsetStateSizes[offsetState & ~gxOffsetInsideLigature];
  343. }
  344.  
  345. static long GetNextOffset(gxShape layout, long offset)
  346. { unsigned short firstGlyph, secondGlyph;
  347.   gxLayoutOffsetState offsetState;
  348.   static long offsetStateSizes[] = {1, 2, 1, 2, 0};
  349.   
  350.   GXGetOffsetGlyphs(layout, offset, 0, &offsetState, &firstGlyph, &secondGlyph);
  351.   
  352.   return offset + offsetStateSizes[offsetState & ~gxOffsetInsideLigature];
  353. }
  354.  
  355. ParagraphRecordHandle NewStyledParagraph(
  356.   long                textRunCount,
  357.   const void          *text[],
  358.   const short         textRunLengths[],
  359.   long                styleRunCount,
  360.   const gxStyle         styles[],
  361.   const short         styleRunLengths[],
  362.   long                levelRunCount,
  363.   const short         levels[],
  364.   const short         levelRunLengths[],
  365.   long                totalByteCount,
  366.   const gxLayoutOptions *layoutOptions,
  367.   Fixed               lineHeight,
  368.   const gxPoint         *firstOrigin)
  369.   {
  370.   /* Variables */
  371.   boolean               startIsStaked;
  372.   gxByteOffset            lineStarts[lineStartsCount], newLineStart, nextStake,
  373.                         nls2, priorStake, thisLineStart;
  374.   char                  *pChar, *pSav;
  375.   Fixed                 currLineDelta, lineAscent, lineDescent;
  376.   gxLayoutOptions         specialOptions;
  377.   ParagraphRecordHandle paraHandle;
  378.   gxShape                 bigLayout, thisLine;
  379.   short                 i, level = 0, nextLineIndex;
  380.   
  381.   specialOptions = *layoutOptions;
  382.   specialOptions.just = specialOptions.flush = 0;
  383.   specialOptions.width = 0;
  384.   
  385.   bigLayout = GXNewLayout(
  386.     textRunCount,
  387.     textRunLengths,
  388.     text,
  389.     styleRunCount,
  390.     styleRunLengths,
  391.     styles,
  392.     levelRunCount,
  393.     levelRunLengths,
  394.     levels,
  395.     &specialOptions,
  396.     firstOrigin);
  397.   
  398.   /* We next compute the gxLine breaks and store the offsets that correspond to them in a
  399.       temporary array. */
  400.   
  401.   thisLineStart = 0;
  402.   nextLineIndex = 0;
  403.   while (thisLineStart < totalByteCount && nextLineIndex < lineStartsCount - 1)
  404.     {
  405.     lineStarts[nextLineIndex++] = thisLineStart;
  406.     newLineStart = GXGetLayoutBreakOffset(
  407.       bigLayout,
  408.       thisLineStart,
  409.       layoutOptions->width,
  410.       0,
  411.       nil,
  412.       &startIsStaked,
  413.       &priorStake,
  414.       &nextStake);
  415.     if (newLineStart == totalByteCount) break;
  416.     /* Now backtrack to first prior space. */
  417.     nls2 = newLineStart;
  418.     pSav = pChar = GetTextPiecePtr(text, textRunLengths, GetPreviousOffset(bigLayout, newLineStart));
  419.     while (nls2 >= lineStarts[nextLineIndex-1] && *pChar != ' ')
  420.       pChar = GetTextPiecePtr(text, textRunLengths, nls2 = GetPreviousOffset(bigLayout, nls2));
  421.  
  422.     if (nls2 <= lineStarts[nextLineIndex-1]) thisLineStart = newLineStart;
  423.     else
  424.       {
  425.       if (pSav != pChar) nls2 = GetNextOffset(bigLayout, nls2);
  426.       thisLineStart = nls2;
  427.       }
  428.     }
  429.   lineStarts[nextLineIndex] = (short) totalByteCount;
  430.   
  431.   /* Allocate space for the ParagraphRecord. */
  432.   
  433.   paraHandle = (ParagraphRecordHandle) NewHandle(
  434.     (Size) (sizeof(ParagraphRecord) + nextLineIndex * sizeof(gxShape)));
  435.   (*paraHandle)->nLayouts = nextLineIndex;
  436.   
  437.   /* Now create the layouts and place them in the ParagraphRecord. */
  438.   
  439.   specialOptions = *layoutOptions;
  440.   currLineDelta = 0;
  441.   
  442.   for (i = 0; i < nextLineIndex; i++)
  443.     {
  444.     if (i == nextLineIndex - 1) specialOptions.just = 0;  /* don't justify last gxLine... */
  445.     thisLine = GXNewLayoutFromRange(
  446.       bigLayout, lineStarts[i], lineStarts[i+1], &specialOptions, nil);
  447.     if (currLineDelta) GXMoveShape(thisLine, 0, currLineDelta);
  448.     (*paraHandle)->layouts[i] = thisLine;
  449.     if (lineHeight) currLineDelta += lineHeight;
  450.     else
  451.       {
  452.       GXGetLayoutSpan(thisLine, &lineAscent, &lineDescent);
  453.       currLineDelta += lineAscent + lineDescent + extraLineGap;
  454.       }
  455.     }
  456.   
  457.   (*paraHandle)->totalHeight = currLineDelta;
  458.   
  459.   GXDisposeShape(bigLayout);
  460.   return paraHandle;
  461.   } /* NewStyledParagraph */
  462.  
  463. /* DisposeParagraph disposes of the memory associated with a paragraph. While currently
  464.     simple, it could be more involved if the paragraph itself retains more information. */
  465.  
  466. void DisposeParagraph(ParagraphRecordHandle paraRec)
  467.   {
  468.   short i;
  469.   for (i = 0; i < (*paraRec)->nLayouts; i++)
  470.     GXDisposeShape((*paraRec)->layouts[i]);
  471.   DisposeHandle((Handle) paraRec);
  472.   } /* DisposeParagraph */
  473.  
  474. /* GetLayoutBounds returns a gxShape corresponding to the bounds of the specified layout. It
  475.     differs from GXGetShapeBounds in two respects: first, it returns a gxShape (rather than just
  476.     a gxRectangle); and second, it takes both the layout's position and its gxMapping into account
  477.     (GXGetShapeBounds only takes the layout's position into account). */
  478.  
  479. gxShape GetLayoutBounds(gxShape layout)
  480.   {
  481.   gxMapping   thisMapping;
  482.   gxRectangle thisRect;
  483.   gxShape     rectShape;
  484.   
  485.   GXGetShapeBounds(layout, 0, &thisRect);
  486.   rectShape = GXNewRectangle(&thisRect);
  487. #if 0
  488.   GXIgnoreGraphicsNotice(transform_already_set);
  489.   GXSetShapeTransform(rectShape, GXGetShapeTransform(layout));
  490.   GXPopGraphicsNotice();
  491. #else
  492.   GXMapShape(rectShape, GXGetTransformMapping(GXGetShapeTransform(layout), &thisMapping));
  493. #endif
  494.   return rectShape;
  495.   } /* GetLayoutBounds */
  496.